package studio.raptor.dispatcher.server;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.curator.framework.recipes.cache.TreeCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import studio.raptor.dispatcher.common.constant.TopicConst;
import studio.raptor.dispatcher.scheduler.ServerScheduler;
import studio.raptor.dispatcher.scheduler.config.ServerConfig;
import studio.raptor.dispatcher.scheduler.config.TaskConfig;
import studio.raptor.dispatcher.server.dao.EventDao;
import studio.raptor.dispatcher.server.dto.EventMetaDataWrapper;
import studio.raptor.dispatcher.server.listeners.ServerTaskListener;
import studio.raptor.dispatcher.server.service.GraphService;
import studio.raptor.hub.out.HubOut;
import studio.raptor.hubout.sdk.properties.ProxyProperties;

/**
 * 分发器初始化，注册到zk，获取任务
 *
 * @author jack
 * @since 1.0
 */
@Component
public class DiapatcherServerInitializer implements ApplicationRunner {

  private static final Logger log = LoggerFactory.getLogger(DiapatcherServerInitializer.class);

  @Autowired
  ServerScheduler serverScheduler;

  @Autowired
  ServerConfig serverConfig;

  @Autowired
  TreeCache server2taskCache;

  @Autowired
  ServerTaskListener serverTaskListener;

  @Autowired
  HubOut hubOut;

  @Autowired
  ApplicationContext context;

  @Autowired
  EventDao eventDao;

  @Autowired
  GraphService graphService;


  @Override
  public void run(ApplicationArguments args) throws Exception {
    //全量更新接口配置
    updateTasks();

    List<String> tasks = hubOut.getCodes();
    log.debug("the hub config task:{}", tasks.toString());

    String server = serverConfig.getHost() + "-" + serverConfig.getPort();
    serverScheduler.uploadServerAbility(tasks, server);
    log.info("server->{},registry to zk", server);
    initListener();
    log.info("recover direct graph......");
    List<String> configTasks = serverScheduler.getTasks(server);
    if (configTasks.isEmpty()) {
      return;
    }
    tasks.retainAll(configTasks);
    log.info("the server [{}] task's [{}]", server, tasks);
    serverScheduler.uploadServerTask(tasks, server);
    List<String> recoverTasks = new ArrayList<>(tasks);
    for (Iterator<String> iterator = recoverTasks.iterator(); iterator.hasNext(); ) {
      String task = iterator.next();
      String code = task.split("-")[0];
      Integer kindId = Integer.valueOf(task.split("-")[1]);
      TaskConfig taskConfig = serverScheduler.getTaskConfig(code, kindId);
      if (!taskConfig.isSort()) {
        iterator.remove();
      }
    }
    recover(recoverTasks);
  }

  /**
   * 初始化节点监听*
   */
  private void initListener() throws Exception {
    server2taskCache.getListenable().addListener(serverTaskListener);
    server2taskCache.start();
  }

  private void recover(List<String> tasks) {
    Map<String, Collection<EventMetaDataWrapper>> allEventByCode = eventDao
        .findAllEventByCode(tasks);
    for (Entry<String, Collection<EventMetaDataWrapper>> entry : allEventByCode.entrySet()) {
      String code = entry.getKey();
      Collection<EventMetaDataWrapper> value = entry.getValue();
      for (EventMetaDataWrapper dataWrapper : value) {
        graphService.sortEvent(code, dataWrapper.getEventMetaData(), dataWrapper.getStatus());
      }
    }
  }

  private void updateTasks() {
    List<ProxyProperties> tasks = hubOut.getTasks();
    for (ProxyProperties task : tasks) {
      TaskConfig taskConfig = new TaskConfig();
      taskConfig.setCode(task.getCode());
      taskConfig.setName(task.getName());
      taskConfig.setKindId(task.getKindId());
      taskConfig.setSort(task.isSort());
      taskConfig.setWeight(Integer.valueOf(task.getLevel()));
      String eventName = TopicConst.kindName.get(task.getKindId());

      taskConfig.setEventName(TopicConst.kindName.get(task.getKindId()));
      Integer type = taskConfig.getKindId() != 8006 ? 0 : 1;
      taskConfig.setType(type);
      serverScheduler.addTask(taskConfig);
    }

  }
}
